﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace DeleteObsoleteContentType
{
    public partial class DeleteObsoleteContentType : Form
    {
        public DeleteObsoleteContentType()
        {
            InitializeComponent();
        }

        private void DeleteObsoleteContentType_Load(object sender, EventArgs e)
        {
            // Display messagebox with warning
            string txtWarningMessage = "This program is designed to look for all deployed instances of a particular Content Type in a certain web application. \n";
            txtWarningMessage += "If the Content Type is not currently being used, it can be removed.  The removal process cannot be undone once complete. \n";
            txtWarningMessage += "This product is provided without charge and there is no warranty expressed or implied.  Use at your own risk. \n";
            if (MessageBox.Show(txtWarningMessage, "Warning:", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
            {
                // user cancelled, exit program
                Application.Exit();
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("CustomRules", "CR0001:CatchBlockWithoutThrow")]  // catch blocks are displaying error message in application
        private void btnActionButton_Click(object sender, EventArgs e)
        {
            // Display messagebox with warning
            string txtWarningMessage = "This program will now loop through the specified web application, covering all site collections and web sites. \n";
            txtWarningMessage += "Nothing will be deleted or modified at this stage. This process can be expected to use 100% of your CPU until it \n";
            txtWarningMessage += "completes and cannot be gracefully stopped in the middle. Please understand the impact that this will have on your \n";
            txtWarningMessage += "systems, test it in a non-production environment and consider using a maintenance window for production environments. \n";
            txtWarningMessage += "\n";
            if (MessageBox.Show(txtWarningMessage, "Warning:", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
            {
                // user cancelled, cancel processing
                return;
            }

            // initiate counters
            int intSiteCollectionCount = 0;
            int intWebSitesCount = 0;

            resetForm();

            // validate and display web application and fill listView
            SPSite spSiteOuter = null;
            try
            {
                // get web application object
                outputThis("Getting web application object for URL: " + txtWebApplicationURL.Text, false);
                spSiteOuter = new SPSite(txtWebApplicationURL.Text);
                SPWebApplication spWebApp = spSiteOuter.WebApplication;
                // display web application name
                outputThis("Displaying web application name for URL: " + txtWebApplicationURL.Text, false);
                lblWebAppNameResult.Text = spWebApp.Name;
                // get site collections
                outputThis("Getting site collection objects for web application: " + spWebApp.Name, false);
                SPSiteCollection spSiteCollections = spWebApp.Sites;
                // loop through site collections
                outputThis("Looping through site collection objects for web application: " + spWebApp.Name, false);
                foreach (SPSite spSiteCollInner in spSiteCollections)
                {
                    try
                    {
                        // loop through webs
                        outputThis("Looping through web site objects for site collection: " + spSiteCollInner.RootWeb.Url, false);
                        foreach (SPWeb spWeb in spSiteCollInner.AllWebs)
                        {
                            try
                            {
                                if (spWeb.IsRootWeb) // web is a site collection
                                {
                                    // increment counter
                                    intSiteCollectionCount = intSiteCollectionCount + 1;
                                    // look for site collection content types
                                    outputThis("Getting content type objects for site collection: " + spSiteCollInner.RootWeb.Url, false);
                                    SPContentTypeCollection spSiteContentTypes = spSiteCollInner.RootWeb.ContentTypes;
                                    // loop through site collection content types
                                    outputThis("Looping through content type objects for site collection: " + spSiteCollInner.RootWeb.Url, false);
                                    foreach (SPContentType spSiteContentType in spSiteContentTypes)
                                    {
                                        // check if content type is in-use
                                        outputThis("Checking usage for content type: " + spSiteContentType.Name, false);
                                        IList<SPContentTypeUsage> usages = SPContentTypeUsage.GetUsages(spSiteContentType);
                                        if (usages.Count == 0) // content type is not used
                                        {
                                            outputThis("This site collection content type can be deleted: " + spSiteContentType.Name, false);
                                            addItemToDataGridView("SiteCollection", true, spSiteContentType.ParentWeb.Url, spSiteContentType.ParentWeb.Title, spSiteContentType.Name, spSiteContentType.Id.ToString());
                                        }
                                        else // content type is used
                                        {
                                            outputThis("This site collection content type: " + spSiteContentType.Name + " cannot be deleted because it is being used in the following places: ", false);
                                            foreach (var usage in usages)
                                            {
                                                outputThis("     " + txtWebApplicationURL.Text.TrimEnd(new char[] { '/' }) + usage.Url, false);
                                            }
                                            addItemToDataGridView("SiteCollection", false, spSiteContentType.ParentWeb.Url, spSiteContentType.ParentWeb.Title, spSiteContentType.Name, spSiteContentType.Id.ToString());
                                        }
                                    }
                                }
                                else // web is not a site collection
                                {
                                    // increment counter
                                    intWebSitesCount = intWebSitesCount + 1;
                                    // look for web site content types
                                    outputThis("Getting content type objects for web site: " + spWeb.Url, false);
                                    SPContentTypeCollection spWebContentTypes = spWeb.ContentTypes;
                                    // loop through web site content types
                                    outputThis("Looping through content type objects for web site: " + spWeb.Url, false);
                                    foreach (SPContentType spWebContentType in spWebContentTypes)
                                    {
                                        // check if content type is in-use
                                        outputThis("Checking usage for content type: " + spWebContentType.Name, false);
                                        IList<SPContentTypeUsage> usages = SPContentTypeUsage.GetUsages(spWebContentType);
                                        if (usages.Count == 0) // content type is not used
                                        {
                                            outputThis("This web site content type can be deleted: " + spWebContentType.Name, false);
                                            addItemToDataGridView("WebSite", true, spWebContentType.ParentWeb.Url, spWebContentType.ParentWeb.Title, spWebContentType.Name, spWebContentType.Id.ToString());
                                        }
                                        else // content type is used
                                        {
                                            outputThis("This web site content type: " + spWebContentType.Name + " cannot be deleted because it is being used in the following places: ", false);
                                            foreach (var usage in usages)
                                            {
                                                outputThis("     " + txtWebApplicationURL.Text.TrimEnd(new char[] { '/' }) + usage.Url, false);
                                            }
                                            addItemToDataGridView("WebSite", false, spWebContentType.ParentWeb.Url, spWebContentType.ParentWeb.Title, spWebContentType.Name, spWebContentType.Id.ToString());
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                outputThis(ex.ToString(), true);
                            }
                            finally
                            {
                                if (spWeb != null)
                                {
                                    spWeb.Dispose();
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        outputThis(ex.ToString(), true);
                    }
                    finally
                    {
                        if (spSiteCollInner != null)
                        {
                            spSiteCollInner.Dispose();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                outputThis(ex.ToString(), true);
            }
            finally
            {
                if (spSiteOuter != null)
                {
                    spSiteOuter.Dispose();
                }
            }

            // update counter labels
            lblSiteCollectionsInWebAppResult.Text = intSiteCollectionCount.ToString();
            lblWebSitesInWebAppResult.Text = intWebSitesCount.ToString();

            // make legend labels and buttons visible
            lblLegend1.Visible = true;
            lblLegend2.Visible = true;
            btnDeleteSelected.Visible = true;

            // output successfully completed looping message
            outputThis("Successfully completed looping through site collections and web sites in web application: " + txtWebApplicationURL.Text, false);
        }

        private void btnDeleteSelected_Click(object sender, EventArgs e)
        {
            // Display messagebox with warning
            string txtWarningMessage = "Deleting/removing selected content types. This process cannot be stopped in the middle and there is no undo function.  \n";
            txtWarningMessage += "Click OK to continue or Cancel to cancel this operation without making any changes. \n";
            txtWarningMessage += "\n";
            if (MessageBox.Show(txtWarningMessage, "Warning:", MessageBoxButtons.OKCancel) == DialogResult.Cancel)
            {
                // user cancelled, cancel processing
                return;
            }

            // loop through selected items and call delete method
            // site collection content types
            outputThis("Looping through selected site collection content types", false);
            foreach (DataGridViewRow row in dgvSiteCollectionContentTypes.Rows)
            {
                if (row.Selected)
                {
                    deleteContentType(row.Cells["colSiteCollectionURL"].Value.ToString(), row.Cells["colSiteCollectionContentTypeName"].Value.ToString(), row.Cells["colSiteCollectionContentTypeID"].Value.ToString());
                }
            }
            outputThis("Complete...  Looping through selected site collection content types", false);

            // web site content types
            outputThis("Looping through selected web site content types", false);
            foreach (DataGridViewRow row in dgvWebSiteContentTypes.Rows)
            {
                if (row.Selected)
                {
                    deleteContentType(row.Cells["colWebSiteURL"].Value.ToString(), row.Cells["colWebSiteContentTypeName"].Value.ToString(), row.Cells["colWebSiteContentTypeID"].Value.ToString());
                }
            }
            outputThis("Complete...  Looping through selected web site content types", false);

            //reset the form
            // Display messagebox with warning
            string txtResetMessageBox = "Do you want to clear all values and reset the form?  \n";
            if (MessageBox.Show(txtResetMessageBox, "Processing Complete...", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                // user wants to clear the form
                resetForm();
            }
        }

        private void outputThis(string strTextToLog, bool boolTextIsError)
        {
            // change label if error
            if (boolTextIsError)
            {
                lblOutput.Text = "Error:";
                lblOutput.ForeColor = System.Drawing.Color.Red;
            }
            // write text to output textbox and break line
            txtOutput.AppendText(strTextToLog);
            txtOutput.AppendText(Environment.NewLine);
            //txtOutput.Text += strTextToLog + "\n";
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("CustomRules", "CR0001:CatchBlockWithoutThrow")]  // catch blocks are displaying error message in application
        private bool deleteContentType(string strSiteOrWebURL, string strContentTypeName, string strContentTypeID)
        {
            // make a bool to hold result
            bool boolSuccessfullyDeleted = false;

            outputThis("Deleting selected content type: " + strContentTypeName + " from: " + strSiteOrWebURL, false);
            // check for usage and delete selected content types
            SPSite spSite = null;
            SPWeb spWeb = null;
            try
            {
                // get site and web objects
                outputThis("Getting site and web objects for: " + strSiteOrWebURL, false);
                spSite = new SPSite(strSiteOrWebURL);
                spWeb = spSite.OpenWeb();

                // get selected content type
                outputThis("Getting selected content type object: " + strContentTypeName + " from: " + strSiteOrWebURL, false);
                // cast content type id string to SPContentTypeID
                SPContentTypeId spContentTypeID = new SPContentTypeId(strContentTypeID);
                SPContentType ctSelectedContentType = spWeb.ContentTypes[spContentTypeID];

                // check if content type exists in web
                outputThis("Checking if content type : " + strContentTypeName + " exists in: " + strSiteOrWebURL, false);
                if (ctSelectedContentType != null) // content type exists in web
                {
                    outputThis("Content type : " + strContentTypeName + " does exist in: " + strSiteOrWebURL, false);
                }
                else // content type does not exist in web
                {
                    outputThis("Content type : " + strContentTypeName + " does not exist in: " + strSiteOrWebURL, true);
                    return boolSuccessfullyDeleted;
                }

                // check if content type is in-use
                outputThis("Checking if content type : " + strContentTypeName + " is currently being used", false);
                IList<SPContentTypeUsage> usages = SPContentTypeUsage.GetUsages(ctSelectedContentType);
                if (usages.Count > 0) // It is in use
                {
                    outputThis("The selected content type: " + strContentTypeName + " cannot be deleted because it is being used in the following places: ", false);
                    foreach (var usage in usages)
                    {
                        outputThis("     " + txtWebApplicationURL.Text.TrimEnd(new char[] { '/' }) + usage.Url, true);
                        return boolSuccessfullyDeleted;
                    }
                }
                else // It is not in use.
                {
                    outputThis("The selected content type: " + strContentTypeName + " is not currently being used", false);
                    // Delete it.
                    outputThis("Deleting selected content type: " + strContentTypeName + " from: " + strSiteOrWebURL, false);
                    spWeb.ContentTypes.Delete(ctSelectedContentType.Id);
                    outputThis("Content type: " + strContentTypeName + " was successfully deleted from: " + strSiteOrWebURL, false);
                    boolSuccessfullyDeleted = true;
                }
            }

            catch (Exception ex)
            {
                outputThis(ex.ToString(), true);
            }

            finally
            {
                if (spWeb != null)
                {
                    spWeb.Dispose();
                }
                if (spSite != null)
                {
                    spSite.Dispose();
                }
            }
            return boolSuccessfullyDeleted;
        }

        private void addItemToDataGridView(string strDataGridViewName, bool boolCanBeDeleted, string strURL, string strSiteOrWebname, string strContentTypeName, string strContentTypeID)
        {
            // create list item

            // check which list to add item to
            if (strDataGridViewName == "SiteCollection")
            {
                outputThis("Adding site collection content type: " + strContentTypeName + " to site collection datagrid", false);
                // add list item to site collection data grid view
                int intRowIndex = dgvSiteCollectionContentTypes.Rows.Add();
                dgvSiteCollectionContentTypes.Rows[intRowIndex].Cells["colSiteCollectionURL"].Value = strURL;
                dgvSiteCollectionContentTypes.Rows[intRowIndex].Cells["colSiteCollectionName"].Value = strSiteOrWebname;
                dgvSiteCollectionContentTypes.Rows[intRowIndex].Cells["colSiteCollectionContentTypeName"].Value = strContentTypeName;
                dgvSiteCollectionContentTypes.Rows[intRowIndex].Cells["colSiteCollectionContentTypeID"].Value = strContentTypeID;

                // color background to indicate if content type can be deleted
                if (boolCanBeDeleted) // content type is not used
                {
                    dgvSiteCollectionContentTypes.Rows[intRowIndex].DefaultCellStyle.BackColor = System.Drawing.Color.LightGreen;
                }
                else // content type is used
                {
                    dgvSiteCollectionContentTypes.Rows[intRowIndex].DefaultCellStyle.BackColor = System.Drawing.Color.LightYellow;
                }
            }
            else if (strDataGridViewName == "WebSite")
            {
                outputThis("Adding web site content type: " + strContentTypeName + " to web site datagrid", false);
                // add list item to site collection data grid view
                int intRowIndex = dgvWebSiteContentTypes.Rows.Add();
                dgvWebSiteContentTypes.Rows[intRowIndex].Cells["colWebSiteURL"].Value = strURL;
                dgvWebSiteContentTypes.Rows[intRowIndex].Cells["colWebSiteName"].Value = strSiteOrWebname;
                dgvWebSiteContentTypes.Rows[intRowIndex].Cells["colWebSiteContentTypeName"].Value = strContentTypeName;
                dgvWebSiteContentTypes.Rows[intRowIndex].Cells["colWebSiteContentTypeID"].Value = strContentTypeID;

                // color background to indicate if content type can be deleted
                if (boolCanBeDeleted) // content type is not used
                {
                    dgvWebSiteContentTypes.Rows[intRowIndex].DefaultCellStyle.BackColor = System.Drawing.Color.LightGreen;
                }
                else // content type is used
                {
                    dgvWebSiteContentTypes.Rows[intRowIndex].DefaultCellStyle.BackColor = System.Drawing.Color.LightYellow;
                }
            }
        }

        private void resetForm()
        {
            // clear previous results
            lblSiteCollectionsInWebAppResult.Text = "";
            lblWebSitesInWebAppResult.Text = "";
            dgvSiteCollectionContentTypes.Rows.Clear();
            dgvWebSiteContentTypes.Rows.Clear();
            lblOutput.Text = "Output:";
            lblOutput.ForeColor = System.Drawing.Color.Black;
            txtOutput.Text = "";
            lblLegend1.Visible = false;
            lblLegend2.Visible = false;
            btnDeleteSelected.Visible = false;
        }
    }
}
